﻿using Dm.filter.log;
using fuzhu;
using LH.Model.ST;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using NETCore.MailKit.Core;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using SqlSuarEntity;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using XXX.api.Log;
using XXX.Bo;
using XXX.Common;
using XXX.Models;

public class ApiLoggingAttribute : ActionFilterAttribute, IOrderedFilter
{
    public int Order => int.MinValue; // 确保最先执行

    private readonly IEmailService _emailService;
    private readonly ILogger<ApiLoggingAttribute> _logger;
    private readonly IConfiguration _configuration;
    private readonly bool _enableEmail;
    private readonly string _emailRecipients;
    private readonly string _emailScope;
    private readonly LoggerHelper _loggerHelper;

    public ApiLoggingAttribute(
        IEmailService emailService,
        ILogger<ApiLoggingAttribute> logger,
        IConfiguration configuration)
    {
        _emailService = emailService;
        _logger = logger;
        _configuration = configuration;
        _loggerHelper = new LoggerHelper();

        // 从配置读取邮件设置
        _enableEmail = _configuration.GetValue<bool>("AppSettings:Mail:Enabled", false);
        _emailScope = _configuration["AppSettings:Mail:SendCope"] ?? "ERROR";
        _emailRecipients = _configuration["AppSettings:Mail:ToAddress"] ?? "";
    }

    public override async Task OnActionExecutionAsync(
        ActionExecutingContext context,
        ActionExecutionDelegate next)
    {
        // 创建日志对象
        var request = context.HttpContext.Request;
        var logInfo = new RequestResponseLog
        {
            Url = request.Path.ToString(),
            Headers = request.Headers.ToDictionary(k => k.Key, v => string.Join(";", v.Value.ToList())),
            Method = request.Method,
            ExcuteStartTime = DateTime.Now
        };

        //// 启用请求缓冲并读取请求体
        ////request.EnableBuffering();
        //using (var reader = new StreamReader(
        //    request.Body,
        //    Encoding.UTF8,
        //    detectEncodingFromByteOrderMarks: true,
        //    bufferSize: 1024,
        //    leaveOpen: true))
        //{
        //    logInfo.RequestBody = await reader.ReadToEndAsync();
        //    request.Body.Position = 0; // 重置流位置
        //}
        if (context.HttpContext.Items.TryGetValue("CachedRequestBody", out var body))
        {
            logInfo.RequestBody = body as string;
        }

        //context.HttpContext.Items["RequestLogInfo"] = logInfo;
        context.HttpContext.Items["LogInfo"] = logInfo;

        // 执行Action
        var executedContext = await next();

        // 处理响应日志
        await ProcessResponseLogging(executedContext);
    }

    private async Task ProcessResponseLogging(ActionExecutedContext context)
    {
        if (!context.HttpContext.Items.TryGetValue("LogInfo", out var logObj) ||
            !(logObj is RequestResponseLog logInfo))
        {
            return;
        }
        var cType = "";
        var cCodeCol = "";
        var cDateCol = "";
        GetApiTypeName(logInfo, out cType, out cCodeCol, out cDateCol);
        logInfo.cName = cType;
        var apiLog = new Zdy_APILog
        {
            id = Guid.NewGuid().ToString(),
            dDate = DateTime.Now.Date,
            dTime = DateTime.Now,
            //cType = context.Controller.GetType().Name,
            cType = cType,
            cText = logInfo.RequestBody,
            iState = context.HttpContext.Response.StatusCode
        };
        //不是json 的不执行这个
        if (!string.IsNullOrEmpty(apiLog.cText) && apiLog.cText.StartsWith("{") && apiLog.cText.EndsWith("}"))
        {
            JObject jObject = JObject.Parse(apiLog.cText);

            string ccode = (string)jObject[cCodeCol];
            if (ccode != null)
            {
                apiLog.cCode = ccode;
            } 
            string ddate = (string)jObject[cDateCol];
            if (ddate != null)
            {
                apiLog.dDate = DbHelper.GetDbDate(ddate);
            }
        }


        try
        {
            // 异常处理（优先级最高）
            if (context.Exception != null)
            {
                apiLog.iState = 500;
                apiLog.cMemo = $"Exception: {context.Exception.Message}";
                if (context.Exception.InnerException != null)
                {
                    apiLog.cMemo += $" | Inner: {context.Exception.InnerException.Message}";
                }

                // 返回自定义错误信息
                context.Result = new JsonResult(DBService.ReErrObject(apiLog.cMemo));
                context.ExceptionHandled = true;
            }
            // 正常响应处理
            else
            {
                // 处理响应结果
                string responseBody = string.Empty;
                if (context.Result is JsonResult jsonResult)
                {
                    responseBody = JsonConvert.SerializeObject(jsonResult.Value);
                    if (jsonResult.Value is RetModel2 retModel)
                    {
                        apiLog.iState = retModel.code;
                        //if (retModel.code != 200)
                        //{
                            apiLog.cMemo = retModel.message;
                        //}
                    }
                }
                else if (context.Result is ObjectResult objectResult)
                {
                    responseBody = JsonConvert.SerializeObject(objectResult.Value);
                    apiLog.iState = objectResult.StatusCode ?? apiLog.iState;
                    if (objectResult.Value is RetModel2 retModel)
                    {
                        apiLog.iState = retModel.code;
                        //if (retModel.code != 200)
                        //{
                            apiLog.cMemo = retModel.message;
                        //}
                    }
                }
                else if (context.Result is ContentResult contentResult)
                {
                    responseBody = contentResult.Content;
                }
                else if (context.Result is StatusCodeResult statusCodeResult)
                {
                    apiLog.iState = statusCodeResult.StatusCode;
                    responseBody = $"Status Code: {statusCodeResult.StatusCode}";
                }

                logInfo.ResponseBody = responseBody;
                if (string.IsNullOrEmpty(apiLog.cMemo))
                {
                    apiLog.cMemo = responseBody;
                }
            }

            // 记录执行结束时间
            logInfo.ExcuteEndTime = DateTime.Now;

            // 记录到日志系统
            _loggerHelper.Debug("API", $"VisitLog: {logInfo}");

            // 异步保存日志（不阻塞请求）
            _ = Task.Run(() =>
            {
                try
                {
                    SqlsugarHelper.Instance.Insertable(apiLog).ExecuteCommand();
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "API日志存储失败");
                }
            });

            // 异步发送邮件通知
            _ = SendNotificationEmailAsync(logInfo, apiLog.iState, apiLog.cMemo);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "API日志处理失败");
            await HandleLoggingError(ex);
        }
    }

    private static void GetApiTypeName(RequestResponseLog logInfo, out string cType, out string cCodeCol, out string cDateCol)
    {
        var urlMappings = new Dictionary<string, (string Type, string CodeCol, string DateCol)>
        {
            ["U8Inventory/Add"] = ("存货档案新增", "cInvCode", "dDate"),            
            ["U8Inventory/BatchAdd"] = ("存货档案批量新增", "cCode", "dDate"),
            ["U8Inventory/Delete"] = ("存货档案删除", "cInvCode", "dDate"),
            ["U8Customer/Add"] = ("客户档案新增", "cCusCode", "dDate"),
            ["U8Customer/BatchAdd"] = ("客户档案批量新增", "cCusCode", "dDate"),
            ["U8Customer/Delete"] = ("客户档案删除", "cCusCode", "dDate"),
            ["U8Vendor/Add"] = ("供应商档案新增", "cVenCode", "dDate"),
            ["U8Vendor/BatchAdd"] = ("供应商档案批量新增", "cVenCode", "dDate"),
            ["U8Vendor/Delete"] = ("供应商档案删除", "cVenCode", "dDate"),
            ["U8Computation/Add"] = ("计量单位新增", "cComUnitCode", "dDate"),
            ["U8Computation/BatchAdd"] = ("计量单位批量新增", "cComUnitCode", "dDate"),
            ["U8Computation/Delete"] = ("计量单位删除", "cComUnitCode", "dDate"),
            ["U8Warehouse/Add"] = ("仓库档案新增", "cInvCcWhCodeode", "dDate"),
            ["U8Warehouse/BatchAdd"] = ("仓库档案批量新增", "cWhCode", "dDate"),
            ["U8Warehouse/Delete"] = ("仓库档案删除", "cWhCode", "dDate"),
            ["U8Position/Add"] = ("货位档案新增", "cPosCode", "dDate"),
            ["U8Position/BatchAdd"] = ("货位档案批量新增", "cPosCode", "dDate"),
            ["U8Position/Delete"] = ("货位档案删除", "cPosCode", "dDate"),
        };

        var found = urlMappings.FirstOrDefault(mapping => logInfo.Url.Contains(mapping.Key));
        if (!found.Equals(default(KeyValuePair<string, (string, string, string)>)))
        {
            (cType, cCodeCol, cDateCol) = found.Value;
        }
        else
        {
            cType = logInfo.Url;
            cCodeCol = "cCode";
            cDateCol = "dDate";
        }
    }

    private async Task SendNotificationEmailAsync(RequestResponseLog logInfo, int statusCode, string errorMessage)
    {
        if (!_enableEmail || string.IsNullOrEmpty(_emailRecipients))
            return;

        // 检查邮件发送条件
        bool shouldSend =
            (_emailScope == "ERROR" && statusCode != 200) ||
            (_emailScope == "ALL");

        if (!shouldSend) return;

        try
        {
            var subject = $"{CanShu.cOrg}-{CanShu.cZT}API访问日志{logInfo.cName}-{(statusCode == 200 ? "成功" : "失败")}";
            var message = new StringBuilder();
            message.AppendLine("<h3>API访问详情</h3>");
            message.AppendLine($"<p><b>时间:</b> {DateTime.Now}</p>");
            message.AppendLine($"<p><b>URL:</b> {logInfo.Url}</p>");
            message.AppendLine($"<p><b>方法:</b> {logInfo.Method}</p>");
            message.AppendLine($"<p><b>状态码:</b> {statusCode}</p>");

            if (!string.IsNullOrEmpty(errorMessage))
            {
                message.AppendLine($"<p><b>错误信息:</b> {errorMessage}</p>");
            }

            message.AppendLine($"<p><b>请求头:</b> {JsonConvert.SerializeObject(logInfo.Headers)}</p>");
            message.AppendLine($"<p><b>请求体:</b> {logInfo.RequestBody}</p>");
            message.AppendLine($"<p><b>响应体:</b> {logInfo.ResponseBody}</p>");

            await _emailService.SendAsync(
                mailTo: _emailRecipients,
                subject: subject,
                message: message.ToString(),
                isHtml: true
            );
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "发送邮件通知时发生错误");
        }
    }

    private async Task HandleLoggingError(Exception ex)
    {
        if (!_enableEmail || string.IsNullOrEmpty(_emailRecipients))
            return;

        try
        {
            await _emailService.SendAsync(
                mailTo: _emailRecipients,
                subject: $"{CanShu.cOrg}-{CanShu.cZT}API日志记录失败",
                message: $"记录API日志时发生错误: {ex.Message}",
                isHtml: false
            );
        }
        catch
        {
            // 忽略邮件发送失败
        }
    }
}